using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Text;
using Commerce.Common;
using Commerce.PayPal;

namespace Commerce.Providers
{
    public class PayPalPaymentProvider : PaymentProvider
    {

        private string _apiUserName;
        private string _apiPassword;
        private string _signature;
        //private string _merchantId;
        private CurrencyCode _defaultCurrencyCode;
        private bool _isLive = false;
        bool authOnly = false;

        #region Provider specific behaviors

        public override void Initialize(string name, NameValueCollection config)
        {
            // Verify that config isn't null
            if (config == null)
                throw new ArgumentNullException("config");

            // Assign the provider a default name if it doesn't have one
            if (String.IsNullOrEmpty(name))
                name = "PayPalPaymentProvider";

            // Add a default "description" attribute to config if the
            // attribute doesn't exist or is empty
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description",
                    "PayPal Payment Provider");
            }
            base.Initialize(name, config);

            _apiUserName = config["apiUserName"].ToString();
            if (String.IsNullOrEmpty(_apiUserName))
                throw new ProviderException("Empty Paypal API UserName (apiUserName) value");

            _apiPassword = config["apiPassword"].ToString();
            if (String.IsNullOrEmpty(_apiPassword))
                throw new ProviderException("Empty Paypal API Password (apiPassword) value");

            _signature = config["signature"].ToString();
            if (string.IsNullOrEmpty(_signature))
                throw new ProviderException("Empty PayPal API Signature (signature) value.");

            //_merchantId = config["merchantId"].ToString();
            //if(String.IsNullOrEmpty(_merchantId))
            //  throw new ProviderException("Empty Merchant ID value");

            string defaultCurrencyCode = config["defaultCurrencyCode"].ToString();
            if (!Enum.IsDefined(typeof(CurrencyCode), defaultCurrencyCode))
            {
                throw new ProviderException("defaultCurrencyCode cannot be parsed to type CurrencyCode.");
            }
            _defaultCurrencyCode = (CurrencyCode)Enum.Parse(typeof(CurrencyCode), defaultCurrencyCode);
            //_defaultCurrencyCode = SiteConfig.CurrencyCode;

            string isLive = config["isLive"].ToString();
            bool isParsed = bool.TryParse(isLive, out _isLive);
            if (!isParsed)
            {
                throw new ProviderException("isLive cannot be parsed to true or false.");
            }
        }

        #endregion

        public override Commerce.Common.Transaction Charge(Commerce.Common.Order order)
        {

            //  API wrapper service
            APIWrapper wrapper = new APIWrapper(_apiUserName, _apiPassword, _signature,
              _defaultCurrencyCode, _isLive);

            Transaction trans = null;

            try
            {
                trans = wrapper.DoDirectCheckout(order, authOnly);
            }
            catch (Exception x)
            {
                //if the URL has "localhost" assume this is dev, so we'll show the error text
                string sUrl = System.Web.HttpContext.Current.Request.UserHostAddress;
                string sMessage = x.Message;

                if (!System.Web.HttpContext.Current.Request.Url.ToString().Contains("localhost"))
                {
                    sMessage += "<br />PayPal Error Message: " + x.Message + "<br /><br />";

                    if (x.Message.IndexOf("country and billing address associated with this credit card do not match") > 0)
                    {
                        sMessage += "Retry the transaction with a different Sandbox Account Number (CC).";
                    }

                    if (x.Message.ToLower().Contains("internal error"))
                    {
                        sMessage += "Retry the transaction with a different Sandbox Account Number (CC) and/or verify the specified currency is supported.";
                    }

                }
                else
                {
                sMessage = "PayPal has rejected this transaction: " + x.Message + sUrl;
                }

                throw new Exception(sMessage);
            }

            return trans;
        }

        public override string Refund(Commerce.Common.Order order)
        {
            APIWrapper wrapper = new APIWrapper(_apiUserName, _apiPassword, _signature,
              _defaultCurrencyCode, _isLive);

            //the PayPal transactionID is stored in the auth code
            string transactionID = order.Transactions[0].AuthorizationCode;

            string sResponse = wrapper.RefundTransaction(transactionID, true);

            if (sResponse != "Success")
            {

                string sMessage = "PayPal has returned an error message for this refund: " + sResponse;
                string encResponse = System.Web.HttpContext.Current.Server.UrlEncode(sResponse);
                if (sMessage.ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("you can not refund this type of transaction (10009)") >= 0)
                    sMessage = "PayPal has rejected the refund of this order for one or more reasons (they don't give exact " +
                        "reasons). If this is a DirectPay (Credit Card) transaction, PayPal will not refund an order if the card for that order is expired. If this is not a DirectPay order, " +
                        "the order is likely too old (greater than 30 days) to be refunded.<br><br>" +
                        "<a href='http://paypal.forums.liveworld.com/search!execute.jspa?q=" + encResponse + "' target=_blank>Find out more</a>";

                throw new Exception(sMessage);

            }
            else
            {
                //PayPal, for some reason, will not return the transactionID
                //this is sort of ridiculous
                //so return a value that means something
                sResponse = order.OrderNumber + "PayPal_REFUND";
            }

            return sResponse;

        }

    }
}
